using System;
using Core;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SolarWinds.Helpers;
using SolarWinds.Input;

namespace SolarWinds.Widgets
{
    public class ScrollBar : TiledWidget
    {
        private enum CursorArea
        {
            None,
            Top,
            Bottom,
            Bar
        }

        private CursorArea mCursorArea = CursorArea.None;

        #region Properties

        private float mMaxValue = 100.0f;

        public float MaxValue
        {
            get { return mMaxValue; }
            set 
            {
                if (value < mMinValue) value = mMinValue;

                mMaxValue = value;

                UpdateScrollButton();
            }
        }

        private float mMinValue;

        public float MinValue
        {
            get { return mMinValue; }
            set 
            {
                if (value > mMaxValue) value = mMaxValue;

                mMinValue = value;

                UpdateScrollButton();
            }
        }

        private float mValue = 50.0f;

        public float Value
        {
            get { return mValue; }
            set 
            {
                if (value < mMinValue) value = mMinValue;
                if (value > mMaxValue) value = mMaxValue;

                mValue = value;

                if (ValueChanged != null)
                {
                    ValueChanged(this, null);
                }

                UpdateScrollButton();
            }
        }

        private Orientation mOrientation = Orientation.Vertical;

        public Orientation Orientation
        {
            get { return mOrientation; }
            set { mOrientation = value; }
        }

        #endregion

        public ScrollBar(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            InitializeRects();
        }

        // TODO public event EventHandler Clicked;
        public event EventHandler Pressed;
        public event EventHandler Released;
        public event EventHandler ValueChanged;

        protected override sealed void InitializeRects()
        {
            mSrcRects = new Rectangle[6];
            mDestRects = new Rectangle[6];
            mTileColors = new Color[6] { Color.White, Color.Tomato, Color.Tomato, 
                                         Color.Tomato, Color.White, Color.White };
        }

        protected override void UpdateSrcDestRects()
        {
            if (mOrientation == Orientation.Vertical)
            {
                // top button
                mSrcRects[0] = TileIndex2Rectangle(new Point(1, 5));
                mDestRects[0] = new Rectangle(ScreenPosition.X, ScreenPosition.Y, Width, mTileSize.Y);
                // top bar
                mSrcRects[1] = TileIndex2Rectangle(new Point(3, 1));
                mDestRects[1] = new Rectangle(ScreenPosition.X, ScreenPosition.Y + mTileSize.Y, Width, mTileSize.Y);
                // middle bar
                mSrcRects[2] = TileIndex2Rectangle(new Point(3, 2));
                mDestRects[2] = new Rectangle(ScreenPosition.X, ScreenPosition.Y + 2 * mTileSize.Y, Width, Height - 4 * mTileSize.Y);
                // bottom bar
                mSrcRects[3] = TileIndex2Rectangle(new Point(3, 3));
                mDestRects[3] = new Rectangle(ScreenPosition.X, ScreenPosition.Y + Height - 2 * mTileSize.Y, Width, mTileSize.Y);
                // bottom button
                mSrcRects[4] = TileIndex2Rectangle(new Point(0, 5));
                mDestRects[4] = new Rectangle(ScreenPosition.X, ScreenPosition.Y + Height - mTileSize.Y, Width, mTileSize.Y);
            }
            else // Orientation.Horizontal
            {
                // left button
                mSrcRects[0] = TileIndex2Rectangle(new Point(2, 5));
                mDestRects[0] = new Rectangle(ScreenPosition.X, ScreenPosition.Y, mTileSize.X, Height);
                // left bar
                mSrcRects[1] = TileIndex2Rectangle(new Point(0, 4));
                mDestRects[1] = new Rectangle(ScreenPosition.X + mTileSize.X, ScreenPosition.Y, mTileSize.X, Height);
                // middle bar
                mSrcRects[2] = TileIndex2Rectangle(new Point(1, 4));
                mDestRects[2] = new Rectangle(ScreenPosition.X + 2 * mTileSize.X, ScreenPosition.Y, Width - 4 * mTileSize.X, Height);
                // right bar
                mSrcRects[3] = TileIndex2Rectangle(new Point(2, 4));
                mDestRects[3] = new Rectangle(ScreenPosition.X + Width - 2 * mTileSize.X, ScreenPosition.Y, mTileSize.X, Height);
                // right button
                mSrcRects[4] = TileIndex2Rectangle(new Point(3, 5));
                mDestRects[4] = new Rectangle(ScreenPosition.X + Width - mTileSize.X, ScreenPosition.Y, mTileSize.X, Height);
            }
            
            UpdateScrollButton();
        }

        private void UpdateScrollButton()
        {
            if (mOrientation == Orientation.Vertical)
            {
                // scroll button
                int buttonHeight = mTileSize.Y; // TODO make variable
                float alpha = (mValue / (mMaxValue - mMinValue));
                var buttonPosition = (int)((ScreenPosition.Y + mTileSize.Y) * (1.0f - alpha) +
                                           (ScreenPosition.Y + Height - 2 * mTileSize.Y) * alpha);// -
                mSrcRects[5] = TileIndex2Rectangle(new Point(2, 0));
                mDestRects[5] = new Rectangle(ScreenPosition.X, buttonPosition, Width, buttonHeight);
            }
            else
            {
                // scroll button
                int buttonWidth = mTileSize.X; // TODO make variable
                float alpha = (mValue / (mMaxValue - mMinValue));
                var buttonPosition = (int)((ScreenPosition.X + mTileSize.X) * (1.0f - alpha) +
                                           (ScreenPosition.X + Width - 2 * mTileSize.X) * alpha);
                mSrcRects[5] = TileIndex2Rectangle(new Point(2, 0));
                mDestRects[5] = new Rectangle(buttonPosition, ScreenPosition.Y, buttonWidth, Height);
            }
        }


        protected internal override void MouseMoveEvent(MouseEvent evt)
        {
            Point absPos = evt.AbsolutePosition;

            // let's find out where our cursor is ...
            if (CheckTile(0, absPos)) mCursorArea = CursorArea.Top;
            else if (CheckTile(4, absPos)) mCursorArea = CursorArea.Bottom;
            else if (CheckTile(5, absPos)) mCursorArea = CursorArea.Bar;
            else mCursorArea = CursorArea.None;

            if (evt.IsConsumed)
            {
                return;
            }

            if (mMoving)
            {
                float alpha;

                if (mOrientation == Orientation.Vertical)
                {
                    alpha = ((float)evt.AbsolutePosition.Y - ScreenPosition.Y - 1.5f * mTileSize.Y) / (Height - 3.0f * mTileSize.Y);
                }
                else
                {
                    alpha = ((float)evt.AbsolutePosition.X - ScreenPosition.X - 1.5f * mTileSize.X) / (Width - 3.0f * mTileSize.X);
                }

                Value = alpha * (mMaxValue - mMinValue);

                evt.Consume();
            }
        }

        private bool CheckTile(int i, Point absPos)
        {
            if (GeometryHelper.Contains(mDestRects[i], absPos))
            {
                mTileColors[i] = Color.Gray;

                return true;
            }
            
            mTileColors[i] = Color.White;

            return false;
        }

        protected internal override void MouseClickEvent(MouseEvent evt)
        {
            if (mCursorArea == CursorArea.Top)
            {
                Value -= 1.0f;
            }
            else if (mCursorArea == CursorArea.Bottom)
            {
                Value += 1.0f;
            }
        }

        protected internal override void MouseOverEvent(MouseEvent evt)
        {
            mTileColors[5] = Color.White;
        }

        protected internal override void MouseOutEvent(MouseEvent evt)
        {
            mTileColors[5] = Color.Tomato;
        }

        private bool mMoving;

        protected internal override void MousePressEvent(MouseEvent evt)
        {
            mMoving = mCursorArea == CursorArea.Bar;

            if (Pressed != null)
            {
                Pressed(this, null);

                evt.Consume();
            }
        }

        protected internal override void MouseReleaseEvent(MouseEvent evt)
        {
            mMoving = false;

            if (Released != null)
            {
                Released(this, null);

                evt.Consume();
            }
        }
    }
}